/**
 * \file ReseauAerien.h
 * \brief Gestion d'un réseau aérien.
 * \author Pierre-Marc Levasseur, Simon Rodier
 * \version 0.1
 * \date juillet 2014
 *
 *  Travail pratique numéro 3
 *
 */

#include "Graphe.h"
#include <iostream>
#include <string>
#include <stdexcept>
#include <climits>
#include <vector>
#include<map>

#ifndef _RESEAUAERIEN__H
#define _RESEAUAERIEN__H



namespace TP3
{

const int infinie = INT_MAX;
const float epsilon = 1.0E-4;

/**
 * \struct Chemin
 *
 * \brief structure qui contient un chemin d'une ville à une autre avec le coût, la durée et le niveau de sécurité
 */
struct Chemin 
{
   std::vector<std::string> listeVilles; /*!< contient la liste des villes formant le chemin */

   float dureeTotale;		/*!< Durée totale du vol du chemin en heures incluant le temps d'escale */
   float coutTotal;			/*!< Cout total en dollars du chemin entre la ville de départ et la ville de destination */
   int nsTotal;				/*!< Niveau de sécurité total du chemin */
   bool reussi;				/*!< Un booléen qui vaut true si chemin a été trouvé, false sinon */
};

//struct VilleDijkstra
//{
//	std::string nomDeVille;
//	std::string origine;
//	float ponder;
//};

struct DonneesVilleDijkstra
{
	std::string origine;
	float ponder;
	bool visite;
};
class ReseauAerien{

public:

	/**                       
	 * \brief constructeur par défaut
	 * \post Un réseau aérien vide est instancié.
	 */
	ReseauAerien(){}  //Le constructeur ne fait rien vu que le type ReseauAerien est composé d'un graphe.
				   //C'est le constructeur de ce dernier qui sera appelé.

	/**                       
	 * \brief Détruit et libère toute la mémoire allouée auparavant pour le réseau aérien.
	 * \post Toute la mémoire allouée auparavant pour le réseau aérien est libérée.
	 * \post L'Objet ReseauAerien n'est plus valide.
	 */
	~ReseauAerien(){}; //Le destructeur ne fait rien, c'est celui du type Graphe qui sera appelé implicitement

	/**
	* \brief Constructeur de copie.
	* \pre Il y a assez de mémoire.
	* \exception bad_alloc S'il n'y a pas assez de mémoire.
	*/
	ReseauAerien(const ReseauAerien &source);
        
    /**
	* \brief Surcharge de l'opérateur d'affectation.
	* \pre Il doit y avoir assez de mémoire.
	* \post Le réseau aérien a un contenu identique à src.
	* \exception bad_alloc S'il n'y a pas assez de mémoire.
	*/
	ReseauAerien& operator=(const ReseauAerien& src);

	/**
	* \brief Surcharge de l'opérateur de sortie.
	* \post Le reseau aérien sera affiché
	*/
	friend std::ostream& operator<<(std::ostream& out, const ReseauAerien& g)
	{
		//on entre les données dans out avec out<<.....
		//il faudrait afficher chaque ville dans le réseau et ses infos, ses destinations, et les informations pour chacune de ses destinations.

		out<<"Réseau aérien: "<<g.nomReseau<<std::endl;
		std::vector<std::string> villes = g.unReseau.listerNomsSommets();
		//on fait le tour des villes
		for(std::vector<std::string>::iterator itVille = villes.begin(); itVille!=villes.end(); itVille++)
		{
			out<<"Ville: "<<*itVille<<std::endl;
			out<<"\tCoordonnées: ("<<g.unReseau.getCoordonneesSommet(*itVille).lt<<
					" , "<<g.unReseau.getCoordonneesSommet(*itVille).lg<<")"<<std::endl;
			std::vector<std::string> destinations = g.unReseau.listerSommetsAdjacents(*itVille);
			out<<"\tDestinations possibles: ";
			if (destinations.size()==0)
			{
				out<<"aucune."<<std::endl;
			}
			else
			{
				for(std::vector<std::string>::iterator itDest = destinations.begin(); itDest!=destinations.end(); itDest++)
				{
					out<<std::endl;
					out<<"\t\t"<<*itDest<<std::endl;
					out<<"\t\t\t"<<"Cout: "<<g.unReseau.getPonderationsArc(*itVille,*itDest).cout<<std::endl;
					out<<"\t\t\t"<<"Durée: "<<g.unReseau.getPonderationsArc(*itVille,*itDest).duree<<std::endl;
					out<<"\t\t\t"<<"Niveau de sécurité: "<<g.unReseau.getPonderationsArc(*itVille,*itDest).ns<<std::endl;
				}
			}

		}
		return out;
	}

	/**                       
	 * \brief Charger un réseau à partir d'un fichier texte en entrée.
	 *  Construit un reseau aérien à partir d'une liste de villes ainsi que leurs liens.
	 * \pre Il y a assez de mémoire pour charger toutes les villes et les trajets du réseau.
	 * \pre fichierEntree est ouvert corectement. 
	 * \post fichierEntree n'est pas fermé par la fonction.
	 * \post Si les préconditions sont respectées, les données du réseau contenu
	 *       dans le fichier en entrée sont organisées dans un graphe en mémoire.
	 * \exception bad_alloc si pas assez de mémoire pour contenir toute la liste du fichier.
	 * \exception logic_error si fichierEntree n'est pas ouvert correctement. 
	 */
	void chargerReseau(std::ifstream & fichierEntree); 

	/**                       
	 * \brief Sauvegarder un réseau dans un fichier texte (voir format du fichier dans l'énoncé du Tp).
	 * \pre SortieFichier est ouvert correctement. 
	 * \post SortieFichier n'est pas fermé par la fonction.
	 * \post Si les préconditions sont respectées, les données du réseau sont sauvegardées dans le fichier.
	 * \exception logic_error si SortieFichier n'est pas ouvert correctement. 
	 */
	void sauvegarderReseau(std::ofstream & SortieFichier) const;

	/**
	* \brief Vider le réseau
	* \post Le reseau est détruit
	*/
	void viderReseau();

	/**
	* \brief Déterminer la fermeture transitive du reseau.
	* \pre Le reseau est correctement initialisé.
	* \post La fermeture transitive du reseau est retournée.
	* \post Le reseau original reste inchangé.
	* \exception bad_alloc si pas assez de mémoire
	*/
	ReseauAerien fermetureReseau();

	/**
	 * \brief Permet de trouver un chemin entre une ville origine et une ville destination
	 *
	 * \pre Il faut que la ville origine et destination fasse partie du réseau aérien
	 * \post le réseau est inchangé
	 *
	 * \exception logic_error si le départ ou l'arrivée ne fait pas partie du réseau aérien
	 */
	std::vector<std::string> rechercheCheminLargeur(const std::string& origine, const std::string& destination);

	/**
	 * \brief Permet de trouver le plus court chemin entre deux ville selon le coût ou la durée du vol
	 *
	 * \pre les ville origine et destination font partie du réseau
	 * \post le réseau est inchangé
	 *
	 * \exception logic_error si une des villes ne fait pas partie du réseau
	 */
	Chemin rechercheCheminDijkstra(const std::string& origine, const std::string& destination, bool dureeCout);

	/**
	 * \brief Permet de trouver le plus court chemin entre deux villes en utilisant les trois différents types de pondérations.
	 *
	 * \pre les ville origine et destination font partie du réseau
	 * \post le réseau est inchangé
	 *
	 * \exception logic_error si une des villes ne fait pas partie du réseau
	 */
	Chemin bellManFord(const std::string& origine, const std::string& destination, int dureeCoutNiveau);

	/**
	 * \brief Permet de trouver le plus court chemin entre deux ville selon le coût ou la durée du vol
	 *
	 * \pre les ville origine et destination font partie du réseau
	 * \post le réseau est inchangé
	 *
	 * \exception logic_error si une des villes ne fait pas partie du réseau
	 */
	Chemin algorithmeAstar(const std::string& origine, const std::string& destination, bool dureeCout);


	/**
	 *  \brief retourne le nom du reseauAerien
	 */
	std::string getNomReseau() const;

	/**
	 *  \brief retourne la taille du reseau aerien (nombre de villes)
	 */
	int getTailleReseau() const;

private:
	Graphe unReseau;			/*!< Le type ReseauAerien est composé d'un graphe */
	std::string nomReseau;		/*!< Le nom du reseau (exemple: Air Canada) */

	/**
	 * \brief Permet de faire le relâchement dans les algorithmes de Dijkstra et Bellman-Ford
	 */
	bool _relachement(const std::string& a, const std::string& b, float c, std::map<std::string, DonneesVilleDijkstra>& map);

	/**
	 * \brief Permet de reconstruire un chemin après l'exécution des algorithmes Dijkstra et Bellman-Ford
	 */
	void _preparerChemin(Chemin& reponse, const std::string& origine, const std::string& destination, std::map<std::string, DonneesVilleDijkstra>& map);

};

}//Fin du namespace

#endif
